package sh.grapendaal.tsuushin.module.uno.engine.domain;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

public class Card implements Comparable<Card>, Playable {
	
	public enum Suit {
		BLUE, GREEN, RED, YELLOW, WILDCARD
	}

	public enum Rank {
		NONE, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, DRAW_TWO, DRAW_FOUR, REVERSE, SKIP
	}

	private Suit suit;
	private Rank rank;
	private Suit nextSuit;

	public Card(Suit suit, Rank rank) {
		this(suit, rank, null);
	}
	
	public Card(Suit suit, Rank rank, Suit nextSuit) {
		this.suit = suit;
		this.rank = rank;
		setNextSuit(nextSuit);
	}
	
	public int getCardValue() {
		if (this.rank.compareTo(Rank.ZERO) >= 0 && this.rank.compareTo(Rank.NINE) <= 0) {
			return this.rank.ordinal() - 1;
		} else if (this.suit == Suit.WILDCARD) {
			// Rank NONE and DRAW_FOUR
			return 50;
		} else {
			// Rank DRAW_TWO, REVERSE and SKIP
			return 20;
		}
	}
	
	@Override
	public int getNumCards() {
		return 1;
	}

	@Override
	public Suit getSuit() {
		return suit;
	}

	@Override
	public Rank getRank() {
		return rank;
	}
	
	public Suit getNextSuit() {
		return nextSuit;
	}

	public void setNextSuit(Suit nextSuit) {
		if (this.suit == Suit.WILDCARD) {
			this.nextSuit = nextSuit;
		}
	}

	@Override
	public Type getType() {
		return Type.CARD;
	}

	@Override
	public boolean validateCard(Card card) {
		if (card.suit == Suit.WILDCARD) {
			// Other card is wildcard.
			return true;
		}
		if (this.suit == card.suit || this.rank == card.rank) {
			// Either suit or rank are the same.
			return true;
		}
		if (this.suit == Suit.WILDCARD && this.nextSuit == card.suit) {
			// We are a wildcard and other card is of the requested suit.
			return true;
		}
		
		return false;
	}

	@Override
	public int compareTo(Card other) {
		int compareSuit = this.suit.compareTo(other.suit);
		if (compareSuit == 0) {
			return this.rank.compareTo(other.rank);
		}
		return compareSuit;
	}

	@Override
	public String toString() {
		return "Card [suit=" + suit + ", rank=" + rank + "]";
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder().append(this.suit).append(this.rank).toHashCode();
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj instanceof Card) {
			Card other = (Card) obj;
			return new EqualsBuilder().append(this.suit, other.suit).append(this.rank, other.rank).isEquals();
		}
		return false;
	}
}
